#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "task.hpp"

// 创建信道类型
class Channel
{
public:
    Channel(int wfd, pid_t subprocessid, const std::string &name)
        : _wfd(wfd), _subprocessid(subprocessid), _name(name)
    {
    }

    ~Channel()
    {
    }

    int Get_wfd() { return _wfd; }
    pid_t Get_processid() { return _subprocessid; }
    std::string Get_name() { return _name; }
    void CloseChannel() { close(_wfd); }
    void Wait()
    {
        int rid = waitpid(_subprocessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait " << rid << " success" << std::endl;
        }
    }

private:
    int _wfd;
    pid_t _subprocessid;
    std::string _name;
};

//void work(int rfd)
//{
//    while (true)
//    {
//        int command = 0;
//        int n = read(rfd, &command, sizeof(command));
//        if (n == sizeof(int))
//        {
//            std::cout << "pid is " << getpid() << " hander task" << std::endl;
//            ExcuteTask(command);
//        }
//       else if (n == 0)
//      {
//            std::cout << " sub process " << getpid() << " quit" << std::endl;
//            break;
//        }
//    }
//}

// 形参类型和命名规范
// const &：输出型参数
// &：输入输出型参数
// *：输出型参数
// 创建信道
void CreatChannelAndSub(int num, std::vector<Channel> *channels,task_t task)
{
    for (int i = 0; i < num; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
            exit(1); // n<0 创建管道失败

        // 创建子进程
        pid_t id = fork();
        
        if (id == 0)
        {
            if(!channels->empty())
            {
                for(auto &channel:*channels)
                {
                    close(channel.Get_wfd());
                }
            }
            // 子进程
            // 关闭不需要的fd
            close(pipefd[1]);
            dup2(pipefd[0],0);// 将写管道信息重定向到标注输入
            task();
            close(0);

            exit(0);
        }
        // 构建一个channel名字
        std::string name = "channel-" + std::to_string(i);

        // 父进程
        close(pipefd[0]);
        channels->push_back(Channel(pipefd[1], id, name));
    }
}

//0 1 2 3 ... channelnum
int nextChannel(int channelnum)
{
    static int next = 0;
    int channel = next;
    next++;
    next %= channelnum;
    return channel;
}

// 发送任务码
void SentTaskCommand(Channel &channel, int taskcommand)
{
    sleep(1);
    write(channel.Get_wfd(), &taskcommand, sizeof(taskcommand));
}


void ctrProcessOnce(std::vector<Channel> &channels)
{
    // a. 选择一个任务
    int taskcommand = SelectTask();
    // b. 选择一个信道和进程
    int cahnnel_indx = nextChannel(channels.size());
    // c. 发送任务
    SentTaskCommand(channels[cahnnel_indx], taskcommand);

    std::cout << std::endl;
    std::cout << "taskcommand: " << taskcommand << ",cahnnel: " << channels[cahnnel_indx].Get_name() << ",sub process: " << channels[cahnnel_indx].Get_processid() << std::endl;
}
// 控制process
void ctrlProcess(std::vector<Channel> &channels, int times = -1)
{
    if (times > 0)
    {
        while (times--)
        {
            ctrProcessOnce(channels);
        }
    }
    else
    {
        while(true)
        {
            ctrProcessOnce(channels);
        }
    }
}

// 回收信道和子进程
 void CleanUpChannel(std::vector<Channel> &channels)
{
    // a. 关闭所有写端
    // b. 回收子进程
   /*  for (auto &channel : channels)
    {
        channel.CloseChannel();
    }
    for (auto &channel : channels)
    {
        channel.Wait();
    } */
   /* int num = channels.size()-1;
   while(num > 0)
   {
        channels[num].CloseChannel();
        channels[num--].Wait();
   } */
   for(auto &channel:channels)
   {
        channel.CloseChannel();
        channel.Wait();
   }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "usage: " << argv[0] << "processnum" << std::endl;
        return 1;
    }

    int num = std::stoi(argv[1]);
    

    Loadtask();
    std::vector<Channel> channels;

    // 创建信道和子进程
    CreatChannelAndSub(num, &channels,work);

    // 通过channel控制子进程
    ctrlProcess(channels,num);

    // 回收管道和子进程
    CleanUpChannel(channels);

    return 0;
}